////////////////////////////////////////////////////////////////////
// Programme de dump/réinsertion des fichiers de Chrono Cross
////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////
// Nemesis pour Terminus Traduction (tt_nemesis@yahoo.fr)
// Date de création :		29/07/03
// Dernière modification :	30/05/04
////////////////////////////////////////////////////////////////////

// Entete
#include "Patcheur.h"

// Type de données pour les Rooms
typedef struct {
	unsigned int adr;
	unsigned char fin;
	unsigned char nb;
} TRoom;

// Noms des fichiers
TRoom Rooms[ROOMS_NB_MAX+(SECTEUR_DONNEES/4)];
int Rooms_nb;

// Taille de l'image en nombre de secteurs
unsigned int adr_max;

/*------------------------------------------------------------------
  Dump des infos de fichiers pointés en début d'iso
------------------------------------------------------------------*/
JNIEXPORT jint JNICALL Java_Librairie_dumpRein_1init
  (JNIEnv *env, jclass cl, jstring i)
{
	// Préparation de l'iso
	const char *iso = env->GetStringUTFChars(i,0);
	if (Iso_Ouvre((char *)iso)!=ERROR_NONE)
		return ERROR_ISO;

	// Numero de pointeur
	short ptr=0;
	short p;
	// Lecture de l'adresse avant traitement
	unsigned int buffer[SECTEUR_DONNEES/4];

	// Taille de l'image
	int taille;
	Iso_Taille(&taille);
	adr_max = taille/SECTEUR_TOTAL;

	// Placement sur la table d'adresses
	Iso_Secteur_Saut(ROOMS_SECT);

	// Initialisation pour la première Room
	ptr=0;
	Rooms[ptr].nb=0;

	while(ptr<ROOMS_NB_MAX) {
		// Changement de secteur
		Iso_Entete_Lit(NON);
		Iso_Adresses_Lit(buffer);

		// Traitement des adresses
		for(p=0;p<(SECTEUR_DONNEES/4);p++) {
			// Plusieurs pointeurs identiques au 0x00800000 près
			Rooms[ptr].nb++;
			// Test du bit de poids fort du 2ème octet (0=ok)
			if (!(buffer[p] & 0x00800000)) {
				Rooms[ptr].fin=(unsigned char)(buffer[p]>>24);
				Rooms[ptr].adr=(buffer[p]<<8)>>8;
				ptr++;
				Rooms[ptr].nb=0;
			}
		}
		Iso_ECC_Saut();
	};
	Rooms_nb=ptr;

	// Creation du dossier temporaire
	mkdir(DIR_BASE);

	return ERROR_NONE;
}

/*------------------------------------------------------------------
  Dump d'un fichier
  la fonction assume que l'iso est déjà ouverte en lecture
--------------------------------------------------------------------
 <- room_num = fichier en question déterminé par son numéro
	dans la table des fichiers
------------------------------------------------------------------*/
JNIEXPORT jint JNICALL Java_Librairie_dumpRein_1dump
  (JNIEnv *env, jclass cl, jint room_num)
{
	// Fichier Room de sortie
	FILE *room_f;
	// Nom du fichier (chemin)
	char room_nom[FICH_MAX];

	// Test du paramètre
	if (room_num<0 || room_num>ROOMS_NB_MAX)
		return ERROR_ROOM;

	// Evaluation du nom de fichier
	sprintf(room_nom,"%s\\%04d",DIR_BASE,room_num);
	// Ouverture du fichier room
	room_f=fopen(room_nom,"wb");
	// Test d'ouverture
	if (room_f==NULL)
		return ERROR_FILE;

	// Placement en début de fichier
	Iso_Secteur_Saut(Rooms[room_num].adr);
	// Parcours du fichier
	while (Iso_Entete_Lit(NON)!=SECT_TFIN) {
		Iso_Donnees_Extrait(room_f,0);
		Iso_ECC_Saut();
	}
	Iso_Donnees_Extrait(room_f,Rooms[room_num].fin);
	fclose(room_f);

	return ERROR_NONE;
}

/*------------------------------------------------------------------
  Réinsertion d'un fichier
  la fonction assume que l'iso est déjà ouverte en lecture
--------------------------------------------------------------------
 <- room_num = fichier en question déterminé par son numéro
	dans la table des fichiers
------------------------------------------------------------------*/
JNIEXPORT jint JNICALL Java_Librairie_dumpRein_1rein
  (JNIEnv *env, jclass cl, jint room_num)
{
	// Infos de lecture du fichier
	_int32 taille,pos;
	_int32 sects,sects_max;
	// Fichier Room de sortie
	FILE *room_f;
	// Nom du fichier (chemin)
	char room_nom[FICH_MAX];
	// Débordement
	int debord;

	// Test du paramètre
	if (room_num<0 || room_num>ROOMS_NB_MAX)
		return ERROR_ROOM;

	// Evaluation du nom de fichier
	sprintf(room_nom,"%s\\%04d",DIR_BASE,room_num);
	// Ouverture du fichier room
	room_f=fopen(room_nom,"rb");
	// Test d'ouverture
	if (room_f==NULL)
		return ERROR_FILE;

	// Taille du fichier d'entrée
	fseek(room_f,0L,SEEK_END);
	taille = ftell(room_f);
	sects = (taille+SECTEUR_DONNEES-1)/SECTEUR_DONNEES;
	fseek(room_f,0L,SEEK_SET);
	// Attention au cas du dernier fichier
	if (Rooms[room_num+1].adr>adr_max
		|| Rooms[room_num+1].adr<Rooms[room_num].adr)
		sects_max = sects;
	else
		sects_max = Rooms[room_num+1].adr
				- Rooms[room_num].adr;
	// Calcul de débordement
	debord=sects-sects_max;
	// Test de débordement
	if (debord>0)
		return ERROR_OVER;

	// Placement en début de fichier
	Iso_Secteur_Saut(Rooms[room_num].adr);
	// Parcours du fichier
	pos=SECTEUR_DONNEES;
	while (pos<taille) {
		Iso_Entete_Modif(SECT_TFICH);
		Iso_Donnees_Insere(room_f);
		pos+=SECTEUR_DONNEES;
	}
	Iso_Entete_Modif(SECT_TFIN);
	Iso_Donnees_Insere(room_f);
	// Mise à jour de la "taille de fin" du fichier
	Rooms[room_num].fin=
		(pos - taille)/8;
	// Fermeture
	fclose(room_f);
	// Suppression du fichier
	remove(room_nom);

	return ERROR_NONE;
}

/*------------------------------------------------------------------
  Réinsertion des infos des fichiers pointés
--------------------------------------------------------------------
 Cette fonction gère la modification des pointeurs de fichiers
 Elle est là pour pouvoir modifier la forme de l'iso en sortie,
 ce qui n'est pas encore implémenté.
------------------------------------------------------------------*/
void dumpRein_pointeursModif (void)
{
	// Numero de pointeur
	short ptr=0;
	short p,n=0;
	// Lecture de l'adresse avant traitement
	unsigned int buffer[SECTEUR_DONNEES/4];

	// Placement sur la table d'adresses
	Iso_Secteur_Saut(ROOMS_SECT);
	while(ptr<ROOMS_NB_MAX && Rooms[ptr].adr<=adr_max) {
		// Changement de secteur
		Iso_Entete_Lit(NON);
		// Traitement des adresses
		for(p=0;p<(SECTEUR_DONNEES/4);p++) {
			buffer[p]=Rooms[ptr].adr;
			// Cas de plusieurs pointeurs identiques
			if (n<Rooms[ptr].nb-1) {
				buffer[p]|=0x00800000;
				n++;
			} else {
				buffer[p]+=Rooms[ptr].fin<<24;
				n=0;
				ptr++;
			}
		}
		Iso_Flush();
		Iso_Adresses_Ecrit(buffer);
	};
}

/*------------------------------------------------------------------
  Fermeture de l'iso et suppression du dossier temporaire
------------------------------------------------------------------*/
JNIEXPORT jint JNICALL Java_Librairie_dumpRein_1close
  (JNIEnv *env, jclass cl)
{
	// Modification de la table de fichiers
	dumpRein_pointeursModif();

	// Fermeture de l'iso
	if (Iso_Ferme()!=ERROR_NONE)
		return ERROR_ISO;

	// Suppression du dossier temporaire
	rmdir(DIR_BASE);

	return ERROR_NONE;
}